package com.tarry.shop.log;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 系统日志切入
 * 可以使用@Order 定义aop切面的优先级，值越小越后执行
 * @author tarry
 * @date 2018/5/7/007
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut( "execution(* com.tarry.shop.*.controller.*.*(..))")
    public void webLog(){}

    /**
     * 声明前置通知
     * @param joinPoint
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //url
        log.info("url={}",request.getRequestURL());
        //method
        log.info("method={}",request.getMethod());
        //ip
        log.info("ip={}",request.getRemoteAddr());
        //class_method 获取类名和方法名称
        log.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
        //args[]
        log.info("args={}",joinPoint.getArgs());
    }

    /**
     * 声明环绕通知
     * around 功能强大 但是必须保证线程安全
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return proceedingJoinPoint.proceed();//调用目标方法
    }

    /**
     * 声明后置通知
     * @param object
     */
    @AfterReturning(pointcut = "webLog()",returning = "object")//打印输出结果
    public void doAfterReturning(Object object){
        log.info("response={}",object.toString());
    }

    @Pointcut( "execution( * com.tarry.shop.*.service.*.*(..))")
    public void serviceLog(){ }

    @Before("serviceLog()")
    public void doServiceBefore(JoinPoint joinPoint){
        log.info("doServiceBefore()");
    }

    @Around("serviceLog()")
    public Object doServiceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("doServiceAround() around");
        return proceedingJoinPoint.proceed();
    }

    @AfterReturning(pointcut = "serviceLog()",returning = "object")//打印输出结果
    public void doServiceAfterReturning(Object object){
        log.info("doServiceAfterReturning={}",object.toString());
    }

}
